﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Xml;
using System.IO;
using System.Windows.Forms;
using DVDFilmoteka.Settings;
using MovieStorage;

namespace DVDFilmoteka.ServerDatabaseManagement
{
    class CSFDServerDatabase : IServerDatabase
    {
        #region constants
        
        private const String SERVERADDRESS = "http://www.csfd.cz";
        private const String SERVERSEARCHPATH = "/hledat/";
        private const String SERVERQUERY = "q";
        private const String USERAGENT = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)";
        private const String XMLPATH_SEARCHRESULTS = "//div[@id='search-films']//a[text()='{0}']";
        private const String XMLPATH_SEARCHRESULTS2 = "//div[@id='search-films']//a[contains(text(),'{0}')]";

        private const String HODNOCENI_XPATH = "//div[@id='rating']/h2";
        private const String ZANRY_XPATH = "//p[@class='genre']";
        private const String CESKYNAZEV_XPATH = "//div[@class='info']/h1";
        private const String ORIGINALNAZEV_XPATH = "//div[@class='info']/ul/li/h3";

        private const String PICTURE_XPATH = "//div[@class='image']/img";
        private const String YEAR_LENGTH_COUNTRY_XPATH = "//p[@class='origin']";
        private const String DIRECTOR_XPATH = "//div[@class='directors']//a";
        private const String DIRECTOR_XPATH2 = "//div[@class='info']/div/span/a";
        //private const String COUNTRY_XPATH = "//p[@class='origin']";
        private const String ACTORS_XPATH = "//div[@class='actors']//a[contains(@href,'tvurce')]";
        private const String ACTORS_XPATH2 = "//div[@class='info']/div[2]/span/a";
        //private const String LENGTH_XPATH = "//p[@class='origin']";
        private const String RECENZE_XPATH = "//div[@id='plots']//div[@class='content']/ul/li";
        
        #endregion

        
        /// <summary>
        /// Vrati adresu stranky s konkretnim filmem
        /// </summary>
        /// <returns>Adresa stranky s filmem</returns>
        private String getFilmPage(String filmName)
        {
            // Ziskat stranku ze serveru
            WebClient client = new WebClient();
            client.Encoding = Encoding.UTF8;
            client.QueryString.Add(SERVERQUERY, filmName);
            client.Headers.Add("user-agent", USERAGENT);
            if (SettingsManager.Instance.Data.UseProxy)
            {
                if (!SettingsManager.Instance.Data.UseDefaultProxy)
                {
                    WebProxy proxy = new WebProxy(SettingsManager.Instance.Data.ProxyIPAddress.ToString(),
                                                  SettingsManager.Instance.Data.ProxyPort);
                    client.Proxy = proxy;
                } else
                {
                    client.Proxy = WebRequest.GetSystemWebProxy();
                }
            }

            byte[] data;
            try
            {
                data = client.DownloadData(SERVERADDRESS + SERVERSEARCHPATH);
            }
            catch (Exception e)
            {
                MessageBox.Show(String.Format(Properties.Messages.messages_servererror, e.Message));
                return null;
            }
            String readData = client.Encoding.GetString(data);
            readData = readData.ToLower();

            const string href = "window.location.href=";
            if (readData.Contains(href))
            {
                readData = readData.Substring(readData.IndexOf(href) + href.Length + 1);
                readData = readData.Substring(0, readData.IndexOf("'"));
                return SERVERADDRESS + readData;
            }

            // Prevest HTML stranku na XML
            XmlDocument document = Tools.convertHtmlToXml(readData);

            // Vyhledat odkaz na stranku s filmem
            String xpath = String.Format(XMLPATH_SEARCHRESULTS, filmName).ToLower();
            XmlNodeList seznamUzlu = document.SelectNodes(xpath);
            if (seznamUzlu == null || seznamUzlu.Count <= 0)
            {
                xpath = String.Format(XMLPATH_SEARCHRESULTS2, filmName).ToLower();
                seznamUzlu = document.SelectNodes(xpath);
                if (seznamUzlu == null || seznamUzlu.Count <= 0)
                {
                    return null;
                }
            }

            // Prhlidnout vsechny nody a najit ten spravny
            String redirect = null;
            foreach (XmlNode uzel in seznamUzlu)
            {
                if (uzel.Attributes.GetNamedItem("href") != null && !String.IsNullOrEmpty(uzel.Attributes.GetNamedItem("href").Value))
                {
                    redirect = uzel.Attributes.GetNamedItem("href").Value;
                    break;
                }
            }
            if (String.IsNullOrEmpty(redirect)) return null;

            return SERVERADDRESS + redirect;            
        }

        #region IServerDatabase Members

        /// <summary>
        /// Nacte udaje o filmu podle zadaneho jmena
        /// </summary>
        /// <param name="filmName"></param>
        /// <returns></returns>
        public MovieDataStore12 getFilmData(String filmName)
        {         
            return getFilmDataFromLink(getFilmPage(filmName));
        }

        /// <summary>
        /// Nacte udaje o filmu podle zadane adresy
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public MovieDataStore12 getFilmDataFromLink(String address)
        {
            if (address == null) return null;

            // Prejit na stranku konkretniho filmu
            WebClient client = new WebClient();
            client.Encoding = Encoding.UTF8;
            client.Headers.Add("user-agent", USERAGENT);
            if (SettingsManager.Instance.Data.UseProxy)
            {
                if (!SettingsManager.Instance.Data.UseDefaultProxy)
                {
                    WebProxy proxy = new WebProxy(SettingsManager.Instance.Data.ProxyIPAddress.ToString(),
                                                  SettingsManager.Instance.Data.ProxyPort);
                    client.Proxy = proxy;
                }
                else
                {
                    client.Proxy = WebRequest.GetSystemWebProxy();
                }
            }
            
            byte[] data;
            try
            {                
                data = client.DownloadData(address);
            }
            catch (Exception)
            {
                return null;
            }
            String readData = client.Encoding.GetString(data);

            // Prevest HTML stranku na XML
            XmlDocument document = Tools.convertHtmlToXml(readData);

            return loadDataFromXML(document, address);
        }

        /// <summary>
        /// Nacte z XML dokumentu udaje o filmu
        /// </summary>
        /// <param name="document"></param>
        /// <param name="linkToFilmPage"></param>
        /// <returns></returns>
        private MovieDataStore12 loadDataFromXML(XmlDocument document, String linkToFilmPage)
        {
            try
            {
                if (document != null)
                {
                    MovieDataStore12 dataStore = new MovieDataStore12();
                    dataStore.link = linkToFilmPage;

                    // Hodnoceni
                    XmlNodeList list = document.SelectNodes(HODNOCENI_XPATH);
                    if (list != null && list.Count > 0 && list[0].FirstChild != null)
                    {
                        dataStore.csfdRating = list[0].FirstChild.Value;
                        if (dataStore.csfdRating == null) //Kdyz je film v 200 nejlepsich tak je hodnoceni posunute
                        {
                            list = document.SelectNodes(HODNOCENI_XPATH);
                            if (list != null && list.Count > 0)
                            {
                                dataStore.csfdRating = list[0].FirstChild.Value;
                            }
                        }
                        if (dataStore.csfdRating != null && dataStore.csfdRating.Contains("%"))
                        {
                            dataStore.csfdRating = dataStore.csfdRating.Trim();
                        }
                        else
                        {
                            dataStore.csfdRating = "N/A";
                        }
                    }
                    else
                    {
                        dataStore.csfdRating = "N/A";
                    }

                    //Zanry
                    list = document.SelectNodes(ZANRY_XPATH);
                    if (list != null && list.Count > 0)
                    {
                        XmlNode node = list[0];
                        String text = node.FirstChild.Value;

                        String[] zanry = text.Split('/');
                        List<GenreItem> zanrList = Tools.getZanrNodeList();

                        // Hlavni zanr
                        String zanrName = zanry[0].Trim();
                        if (zanrName.Contains("&"))
                        {
                            zanrName = zanrName.Substring(0, zanrName.IndexOf("&"));
                        }
                        dataStore.otherGenre.Add(Tools.GetGenreByName(zanrName, false).ID);
                        dataStore.mainGenre = Tools.GetGenreByName(zanrName, false).Name;

                        // Vedlejsi zanry
                        for (int i = 1; i < zanry.Length; i++)
                        {
                            zanrName = zanry[i].Trim();
                            if (zanrName.Contains("&")) //Text byva ukoncen nejakym XML znakem
                            {
                                zanrName = zanrName.Substring(0, zanrName.IndexOf("&"));
                            }
                            dataStore.otherGenre.Add(Tools.GetGenreByName(zanrName, false).ID);
                        }
                    }

                    //Cesky nazev
                    list = document.SelectNodes(CESKYNAZEV_XPATH);
                    if (list != null && list.Count > 0)
                    {
                        XmlNode node = list[0];
                        String text = node.FirstChild.Value;

                        dataStore.czechName = text.Trim();
                    }
                    else
                    {
                        dataStore.czechName = "";
                    }

                    //Original nazev
                    list = document.SelectNodes(ORIGINALNAZEV_XPATH); //Na normalnim miste
                    if (list != null && list.Count > 0)
                    {
                        XmlNode node = list[0];
                        String text = node.FirstChild.Value;

                        dataStore.originalName = text.Trim();
                    }
                    else
                    {
                        dataStore.originalName = dataStore.czechName;
                    }

                    // Obrazek
                    list = document.SelectNodes(PICTURE_XPATH); //Na normalnim miste
                    if (list != null && list.Count > 0)
                    {
                        XmlNode node = list[0];
                        String text = node.Attributes.GetNamedItem("src").Value;

                        dataStore.pictureLink = text;
                    }
                    else
                    {
                        dataStore.pictureLink = "";
                    }

                    // Zeme, Delka, Rok
                    list = document.SelectNodes(YEAR_LENGTH_COUNTRY_XPATH);
                    if (list != null && list.Count > 0)
                    {
                        XmlNode node = list[0];
                        if (node != null && node.InnerText != null)
                        {
                            String text = node.InnerText;

                            String[] datas = text.Split(',');

                            if (datas.Length > 0) dataStore.country = datas[0].Trim();
                            if (datas.Length > 1) dataStore.year = datas[1].Trim();
                            if (datas.Length > 2) dataStore.length = datas[2].Trim();
                        }
                        else
                        {
                            dataStore.country = "";
                            dataStore.length = "";
                            dataStore.year = "";
                        }
                    }
                    else
                    {
                        dataStore.country = "";
                        dataStore.length = "";
                        dataStore.year = "";
                    }

                    // Reziser
                    list = document.SelectNodes(DIRECTOR_XPATH);
                    if (list == null || list.Count <= 0) list = document.SelectNodes(DIRECTOR_XPATH2);

                    if (list != null && list.Count > 0)
                    {
                        XmlNode node = list[0];
                        String text = node.FirstChild.Value;

                        dataStore.directorName = text.Replace("&nbsp;", " ").Trim();
                        if (node.Attributes["href"] != null)
                        {
                            dataStore.directorLink = SERVERADDRESS + node.Attributes["href"].Value;
                        }
                        else
                        {
                            dataStore.directorLink = "";
                        }
                    }
                    else
                    {
                        dataStore.directorName = "";
                        dataStore.directorLink = "";
                    }

                    // Herci
                    list = document.SelectNodes(ACTORS_XPATH);
                    if (list == null || list.Count <= 0) list = document.SelectNodes(ACTORS_XPATH2);

                    if (list != null && list.Count > 0)
                    {
                        foreach (XmlNode node in list)
                        {
                            String name = node.FirstChild.Value;
                            String link = "";

                            name = name.Replace("&nbsp;", " ").Trim();
                            if (node.Attributes["href"] != null)
                            {
                                link = SERVERADDRESS + node.Attributes["href"].Value;
                            }
                            else
                            {
                                link = "";
                            }

                            if (!String.IsNullOrEmpty(name))
                            {
                                if (dataStore.actors.ContainsKey(name)) // Klic jiz existuje, muze se stat, kdyz je vice hercu se stejnym jmenem
                                {
                                    for (int i = 2; i < 150; i++) // Projet a pridat za jmeno cislo
                                    {
                                        if (!dataStore.actors.ContainsKey(name + "_" + i))
                                        {
                                            dataStore.actors.Add(name + "_" + i, link);
                                            break;
                                        }
                                    }
                                }
                                else
                                {
                                    dataStore.actors.Add(name, link);
                                }
                            }
                        }
                    }
                    else
                    {
                        dataStore.actors = new SerializableDictionary<string, string>();
                    }

                    // Recenze
                    dataStore.recenze = "";
                    list = document.SelectNodes(RECENZE_XPATH);
                    if (list != null && list.Count > 0)
                    {
                        XmlNode node = list[0];
                        String text = node.FirstChild.Value;
                        if (String.IsNullOrEmpty(text)) text = node.FirstChild.InnerText;

                        if (!String.IsNullOrEmpty(text))
                        {
                            text = text.Trim();
                            text = text.Replace("&nbsp;", "");
                            dataStore.recenze = text;
                        }
                    }

                    return dataStore;
                }
            }
            catch (Exception)
            {
                MessageBox.Show(Properties.Messages.messages_filmloadproblem, Properties.Messages.form_about_labelProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);                
            }
            return null;
        }       

        #endregion
    }
}